package hos.kotlin

import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.channels.FileChannel
import java.text.DecimalFormat
import java.util.*
import java.util.regex.Pattern

/**
 * <p>Title: StringExt </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @date : 2022/5/20 22:30
 * @version : 1.0
 */

/**
 * 是否为浮点数, 无论Float或者Double
 * @receiver String
 * @return Boolean
 */
fun String.isDouble(): Boolean {
    val pattern = Pattern.compile("^[-\\+]?[.\\d]*$")
    return pattern.matcher(this).matches()
}

/**
 * 是否为整数
 * @receiver String
 * @return Boolean
 */
fun String.isInteger(): Boolean {
    val pattern = Pattern.compile("^[-\\+]?[\\d]*$")
    return pattern.matcher(this).matches()
}


/**
 * 是否是数字
 * @receiver String
 * @return Boolean
 */
fun String.isNumber(): Boolean {
    return if (this == ".") {
        false
    } else {
        isDouble() || isInteger()
    }
}

//</editor-fold>
/**
 * 截取字符串左侧指定长度的字符串
 * @param count 截取长度
 * @return 截取字符串
 */
fun String?.subLeft(count: Int): String {
    val empty = toNullString() ?: return ""
    return empty.substring(0, Math.min(count, empty.length))
}

/**
 * 截取字符串右侧指定长度的字符串
 *
 * @param count 截取长度
 * @return 截取字符串
 * Summary 其他编码的有待测试
 */
fun String?.subRight(count: Int): String? {
    val empty = toNullString() ?: return ""
    return empty.substring(empty.length - Math.min(count, empty.length), empty.length)
}

fun String?.deleteEndZero(): String {
    var value = toNullString() ?: return ""
    if (value.indexOf(".") > 0) {
        value = value.replace("0+?$".toRegex(), "") //去掉多余的0
        value = value.replace("[.]$".toRegex(), "") //如最后一位是.则去掉
    }
    return value
}

fun String?.format(format: String = "#.##"): String {
    return try {
        val orEmpty = orEmpty()
        val numberFormat = DecimalFormat(format)
        val result = numberFormat.format(orEmpty)
        if (result.orEmpty().isEmpty()) {
            return "0"
        }
        if (result == ".00") {
            return "0"
        }
        if (result.contains(".") && "." == result.substring(0, 1)) {
            "0$result"
        } else result
    } catch (e: Exception) {
        e.printStackTrace()
        "0"
    }
}


//<editor-fold desc="URL">
fun String?.url(isHttps: Boolean = false, ip: String? = null): String {
    val url = this.toNullString() ?: ""
    if (url.contains("http://")) {
        return url
    } else if (url.contains("https://")) {
        return url
    } else {
        if (ip.isNullOrEmpty()) {
            if (isHttps) {
                return "https://$url"
            }
            return "http://$url"
        }
        if (ip.startsWith("http")) {
            return "$ip$url"
        }
        if (isHttps) {
            return "https://$ip$url"
        }
        return "http://$ip$url"
    }
}

fun String?.httpIp(): String? {
    val url = this.toNullString() ?: ""
    return if (url.contains("?")) {
        url.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
    } else url
}

fun String?.urlParams(): MutableMap<String, String?> {
    val url = this.toNullString() ?: ""
    val map = mutableMapOf<String, String?>()
    if (url.contains("?")) {
        val paramStr = url.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
        if (paramStr.contains("&")) {
            val params = paramStr.split("&".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            for (param in params) {
                if (param.contains("=")) {
                    val paramSplit = param.split("=".toRegex()).dropLastWhile { it.isEmpty() }
                        .toTypedArray()
                    if (paramSplit.size == 1) {
                        map[paramSplit[0]] = null
                    } else {
                        map[paramSplit[0]] = paramSplit[1]
                    }
                }
            }
            return map
        }
        if (paramStr.contains("=")) {
            val paramSplit = paramStr.split("=".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            if (paramSplit.size == 1) {
                map[paramSplit[0]] = null
            } else {
                map[paramSplit[0]] = paramSplit[1]
            }
        }
        return map
    }
    if (url.contains("&")) {
        val params = url.split("&".toRegex()).dropLastWhile { it.isEmpty() }
            .toTypedArray()
        for (param in params) {
            if (param.contains("=")) {
                val paramSplit = param.split("=".toRegex()).dropLastWhile { it.isEmpty() }
                    .toTypedArray()
                if (paramSplit.size == 1) {
                    map[paramSplit[0]] = null
                } else {
                    map[paramSplit[0]] = paramSplit[1]
                }
            }
        }
        return map
    }
    if (url.contains("=")) {
        val paramSplit = url.split("=".toRegex()).dropLastWhile { it.isEmpty() }
            .toTypedArray()
        if (paramSplit.size == 1) {
            map[paramSplit[0]] = null
        } else {
            map[paramSplit[0]] = paramSplit[1]
        }
    }
    return map
}
//</editor-fold>


/**
 * 剔除返回xml中的类型
 *
 * @param body 处理目标
 * @return 返回值
 */
fun String?.toSoap(): String {
    return this.empty()
        .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>".toRegex(), "")
        .replace("\n".toRegex(), "")
        .replace("\t".toRegex(), "")
        .replace("\r".toRegex(), "")
        .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>".toRegex(), "")
        .replace("<boolean xmlns=\"http://tempuri.org/\">".toRegex(), "")
        .replace("<long xmlns=\"http://tempuri.org/\">".toRegex(), "")
        .replace("<double xmlns=\"http://tempuri.org/\">".toRegex(), "")
        .replace("<int xmlns=\"http://tempuri.org/\">".toRegex(), "")
        .replace("<string xmlns=\"http://tempuri.org/\">".toRegex(), "")
        .replace("</string>".toRegex(), "")
        .replace("</int>".toRegex(), "")
        .replace("</double>".toRegex(), "")
        .replace("</long>".toRegex(), "")
        .replace("</boolean>".toRegex(), "")
        .replace("</xml>".toRegex(), "")
        .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
        .replace("\n", "")
        .replace("\t", "")
        .replace("\r", "")
        .replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "")
        .replace("<boolean xmlns=\"http://tempuri.org/\">", "")
        .replace("<long xmlns=\"http://tempuri.org/\">", "")
        .replace("<double xmlns=\"http://tempuri.org/\">", "")
        .replace("<int xmlns=\"http://tempuri.org/\">", "")
        .replace("<string xmlns=\"http://tempuri.org/\">", "")
        .replace("</string>", "")
        .replace("</double>", "")
        .replace("</long>", "")
        .replace("</boolean>", "")
        .replace("</xml>", "").trim { it <= ' ' }
}

//</editor-fold>

//<editor-fold desc="Length">
fun String?.fontLength(): Int {
    val target: String = empty().replace("[^\\x00-\\xff]", "**")
    var strLength = 0
    val chinese = "[\u0391-\uFFE5]".toRegex()
    /* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */
    for (i in target.indices) {
        /* 从字符串中获取一个字符 */
        val temp = target.substring(i, i + 1)
        strLength += if (temp.matches(chinese)) {
            /* 判断是否为中文字符 */
            /* 中文字符长度为2 */
            2
        } else {
            /* 其他字符长度为1 */
            1
        }
    }
    return strLength
}

fun Int.addLength(): String {
    val newString = StringBuilder()
    for (i in 0 until this) {
        newString.append(" ")
    }
    return newString.toString()
}

fun String?.addLength(allLength: Int): String {
    val target = toNullString() ?: ""
    val spaceLength = allLength - target.fontLength() - 1
    val newString = StringBuilder(" $target")
    for (i in 0 until spaceLength) {
        newString.append(" ")
    }
    return newString.toString()
}

fun String?.addLengthCenter(allLength: Int): String {
    var target = toNullString() ?: ""
    val spaceLength: Int = (allLength - target.fontLength()) / 2
    for (i in 0 until spaceLength) {
        target = " $target "
    }
    return target
}
//</editor-fold>

//<editor-fold desc="File">
fun String.fileSize(): Long {
    return File(this).fileSize()
}

fun File.fileSize(): Long {
    val file: File = this
    val length = file.length()
    if (length != 0L) {
        return length
    }
    var channel: FileChannel? = null
    var fileInputStream: FileInputStream? = null
    return try {
        fileInputStream = FileInputStream(file)
        channel = fileInputStream.channel
        channel.size()
    } catch (ignored: IOException) {
        0
    } finally {
        if (fileInputStream != null) {
            try {
                fileInputStream.close()
            } catch (ignored: IOException) {
            }
        }
    }
}

fun Long?.formatFileSize(): String {
    val size: Long = this.asLong()
    val df = DecimalFormat("#.00")
    var fileSizeString = ""
    val wrongSize = "0B"
    if (size == 0L) {
        return wrongSize
    }
    fileSizeString = if (size < 1024) {
        df.format(size.toDouble()) + "B"
    } else if (size < 1048576) {
        df.format(size.toDouble() / 1024) + "KB"
    } else if (size < 1073741824) {
        df.format(size.toDouble() / 1024) + "MB"
    } else if (size < 1099511627776L) {
        df.format(size.toDouble() / 1073741824) + "GB"
    } else if (size < 1125899906842624L) {
        df.format(size.toDouble() / 1099511627776L) + "TB"
    } else {
        df.format(size.toDouble() / 1125899906842624L) + "PB"
    }
    return fileSizeString
}

fun String.formatFileSize(): String {
    return fileSize().formatFileSize()
}

fun File.formatFileSize(): String {
    return fileSize().formatFileSize()
}
//</editor-fold>